package com.jameskarl.amap.map

import android.app.Activity
import android.app.Application
import android.content.Context
import android.content.res.AssetFileDescriptor
import android.os.Bundle
import android.util.Log
import android.view.View
import com.amap.api.maps.AMap
import com.amap.api.maps.CameraUpdateFactory
import com.amap.api.maps.TextureMapView
import com.amap.api.maps.model.BitmapDescriptorFactory
import com.amap.api.maps.model.MyLocationStyle
import com.jameskarl.amap.AmapPlugin
import com.jameskarl.amap.map.apis.LocationService
import com.jameskarl.amap.map.apis.MarkerIconFactory
import com.jameskarl.amap.map.bean.MapCreationParams
import io.flutter.plugin.common.PluginRegistry
import io.flutter.plugin.platform.PlatformView

class PlatformMapView(
        context: Context,
        id: Int,
        private val registrar: PluginRegistry.Registrar,
        private val creationParams: MapCreationParams? = null
) : PlatformView, Application.ActivityLifecycleCallbacks {

    private val mapView: TextureMapView = TextureMapView(context)
    private val messageHandler: MapMessageHandler = MapMessageHandler(registrar, mapView, id)

    private val registrarActivityHashCode: Int = registrar.activity().hashCode()
    private var disposed = false

    init {
        pluginRegistrar = registrar
        setup()
        messageHandler.setup()
    }

    override fun getView(): View {
        return mapView
    }

    override fun dispose() {
        if (disposed) {
            return
        }

        disposed = true
        registrar.activity().application.unregisterActivityLifecycleCallbacks(this)
        mapView.onDestroy()
    }

    private fun setup() {
        mapView.onCreate(null)
        registrar.activity().application.registerActivityLifecycleCallbacks(this)
        initWithCreationParams()
        LocationService.init(context = registrar.activity().applicationContext)
    }

    private fun initWithCreationParams() {
        val params = creationParams
        if (params != null) {
            val mapSettings = mapView.map.uiSettings
            val aMap = mapView.map

            aMap.isMyLocationEnabled = true

            params.cameraPosition?.apply {
                if (valid()) {
                    aMap.moveCamera(CameraUpdateFactory.newCameraPosition(toCameraPosition()))
                }
                minZoom?.let { aMap.minZoomLevel = it.toFloat() }
                maxZoom?.let { aMap.maxZoomLevel = it.toFloat() }
            }

            params.settings?.apply {
                getAMapLogoPosition()?.let { mapSettings.logoPosition = it }
                getAMapZoomPosition()?.let { mapSettings.zoomPosition = it }
                compassEnabled?.let { mapSettings.isCompassEnabled = it }
                gestureScaleByMapCenter?.let { mapSettings.isGestureScaleByMapCenter = it }
                indoorSwitchEnabled?.let { mapSettings.isIndoorSwitchEnabled = it }
                myLocationButtonEnabled?.let { mapSettings.isMyLocationButtonEnabled = it }
                myLocationEnabled?.let { aMap.isMyLocationEnabled = it }
                rotateGesturesEnabled?.let { mapSettings.isRotateGesturesEnabled = it }
                scaleControlsEnabled?.let { mapSettings.isScaleControlsEnabled = it }
                scrollGesturesEnabled?.let { mapSettings.isScrollGesturesEnabled = it }
                tiltGesturesEnabled?.let { mapSettings.isTiltGesturesEnabled = it }
                zoomControlsEnabled?.let { mapSettings.isZoomControlsEnabled = it }
                zoomGesturesEnabled?.let { mapSettings.isZoomGesturesEnabled = it }
                allGesturesEnabled?.let { mapSettings.setAllGesturesEnabled(it) }

            }

            aMap.myLocationStyle = MyLocationStyle().also { style ->
                params.myLocationStyle?.apply {
                    getAMapMyLocationType()?.let { style.myLocationType(it) }
                    radiusFillColor?.let { style.radiusFillColor(it.toInt()) }
                    strokeColor?.let { style.strokeColor(it.toInt()) }
                    strokeWidth?.let { style.strokeWidth(it.dp) }
                    interval?.let { style.interval(it) }
                    myLocationIcon?.let {
                        registrar.lookupKeyForAsset(it)?.let { assetName ->
                            if (AmapPlugin.showDebugMessage) Log.d("MAP", "flutter asset $it -> android asset $assetName")
                            style.myLocationIcon(BitmapDescriptorFactory.fromAsset(assetName))
                        }
                    }
                }
            }
        }
    }

    override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
        if (!hasDisposed(activity)) {
            mapView.onCreate(savedInstanceState)
        }
    }

    override fun onActivityStarted(activity: Activity) {
        //np
    }

    override fun onActivityResumed(activity: Activity) {
        if (!hasDisposed(activity)) {
            mapView.onResume()
        }
    }

    override fun onActivityPaused(activity: Activity) {
        if (!hasDisposed(activity)) {
            mapView.onPause()
        }
    }

    override fun onActivityStopped(activity: Activity) {
        //np
    }

    override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle?) {
        if (!hasDisposed(activity)) {
            mapView.onSaveInstanceState(outState)
        }
    }

    override fun onActivityDestroyed(activity: Activity) {
        if (!hasDisposed(activity)) {
            mapView.onDestroy()
        }
    }

    private fun hasDisposed(activity: Activity) =
            disposed || activity.hashCode() != registrarActivityHashCode

    companion object {
        var markerIconFactory: MarkerIconFactory? = null
        var infoWindowAdapter: AMap.InfoWindowAdapter? = null
        internal var pluginRegistrar: PluginRegistry.Registrar? = null

        fun getActivity(): Activity? = pluginRegistrar?.activity()

        internal fun getFlutterAsset(relativePath: String, iconPackage: String? = null): AssetFileDescriptor? {
            val registrar = pluginRegistrar ?: return null
            val assetManager = registrar.context().assets
            val key = if (iconPackage == null) registrar.lookupKeyForAsset(relativePath) else registrar.lookupKeyForAsset(relativePath, iconPackage)
            return try {
                assetManager.openFd(key)
            } catch (e: Throwable) {
                e.printStackTrace()
                null
            }
        }
    }
}